package com.macrounion.atv.listener;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.macrounion.atv.cache.ChannelCache;
import com.macrounion.atv.cache.DeviceCache;
import com.macrounion.atv.processor.ChannelProcessor;
import com.macrounion.atv.processor.CurrentDataProcessor;
import com.macrounion.atv.processor.RegProcessor;
import com.macrounion.atv.service.entity.Channel;
import com.macrounion.atv.service.entity.CurrentData;
import com.macrounion.atv.service.entity.ext.DeviceExt;
import com.macrounion.atv.service.service.CurrentDataService;
import com.macrounion.device.resolver.dto.MuDeviceAttrDetailDto;
import com.macrounion.device.resolver.dto.MuDeviceAttrDto;
import com.macrounion.device.resolver.dto.MuDeviceAttrDto.Type;

/**
 * 捷宸接收数据Listener
 *
 * @author Administrator
 */
@Component
public class DataReceiveListener {
    private static Logger logger = LoggerFactory.getLogger(DataReceiveListener.class);
    private static Logger dataLogger = LoggerFactory.getLogger("com.macrounion.atv");

    @Autowired
    private DeviceCache deviceCache;
    @Autowired
    private ChannelCache channelCache;
    @Autowired
    private ChannelProcessor channelProcessor;
    @Autowired
    private CurrentDataProcessor currentDataProcessor;
    @Autowired
    private CurrentDataService currentDataService;
    @Autowired
    private RegProcessor regProcessor;
	@Autowired
	private LoadingCache<String,Date> oprateCache;

    public void receive(String channelKey, MuDeviceAttrDto dt) {
    	MuDeviceAttrDto dto = new MuDeviceAttrDto();
    	BeanUtils.copyProperties(dt, dto);
    	if(!regProcessor.canUse()|| !canReceive(dto.getCode()))
			return;
        CurrentDeviceData currentDeviceData = deviceAttrDto2CurrentDeviceData(channelKey,dto);
    	if(currentDeviceData!=null) {
    		List<CurrentData> resp = Lists.newArrayList();
    		if(currentDeviceData.getDevice() != null)
    			resp = currentDataProcessor.saveDataFromSnmp(currentDeviceData.getDevice().getId(),currentDeviceData.getDetails(),"curdata");
    		else if(!CollectionUtils.isEmpty(currentDeviceData.getDetails()))
    			currentDataService.saveData(currentDeviceData.getDetails());
    		//存储虚拟通道
    		if(currentDeviceData.getDevice() != null&&!CollectionUtils.isEmpty(currentDeviceData.getDetails()) && !CollectionUtils.isEmpty(resp))
    			currentDeviceData.getDetails().forEach(d->{
					Channel c = channelCache.getChannel(d.getDeviceId(), d.getChannelCode());
					if(c!=null && StringUtils.isEmpty(c.getVirtualId())) {
						channelProcessor.saveVirtual(currentDeviceData.getDevice(), c);
					}
				});
    	}
    		
    }

    private CurrentDeviceData deviceAttrDto2CurrentDeviceData(String channelKey,MuDeviceAttrDto dto) {
    	if(dto == null || CollectionUtils.isEmpty(dto.getDetails()))
    		return null;
//    	logger.info(dto.getCode());
    	CurrentDeviceData resp = new CurrentDeviceData();
    	resp.setIp(dto.getCode());
    	DeviceExt device = deviceCache.getDevice(dto.getCode());
    	if(device != null && device.getStype().toLowerCase().equals("snmp"))
    		return null;//snmp设备不能走socket发送
    	resp.setDevice(device);
    	List<CurrentData> datas = Lists.newArrayList();
    	String type = dto.getType();
    	dto.getDetails().forEach(d->{
    		if(!StringUtils.isEmpty(d.getCode())) {
    		CurrentData data = new CurrentData();
    		data.setChannelCode(d.getCode());
			Channel c = null;
			if(device != null) {
				data.setDeviceId(device.getId());
				c=channelCache.getChannel(device.getId(), d.getCode());
				data.setDeviceCode(device.getDeviceCode());
				data.setSpotId(device.getSpotId());
			}else {
				data.setDeviceCode(dto.getCode());
			}
			data.setId(UUID.randomUUID().toString());
			data.setCreatedTime(new Date());
			if(c!=null) {
				data.setChannelId(c.getId());
				data.setShowValue(channelProcessor.getVaule(c,d.getValue()));
				data.setUnit(c.getUnit());
				data.setValues(d.getValue());
				Integer ala = getAlarm(type,d,c,data.getShowValue());
				data.setAlarm(ala);
				if(device != null)
					channelProcessor.sendAlarmToItu(device,c,data);
			}else {
				data.setUnit(d.getUnit());
				data.setAlarm(getAlarm(type,d,null,data.getShowValue()));
				data.setValues(d.getValue());
				data.setShowValue(d.getValue());
				data.setChannelId(d.getName());
			}
			datas.add(data);
    		}
    	});
    	resp.setDetails(datas);
        return resp;
    }

    /**
     * 是否告警
     * @param type 
     * @param d
     * @param c
     * @param showValue
     * @return
     */
	private Integer getAlarm(String type, MuDeviceAttrDetailDto d, Channel c, String showValue) {
		if(d.getAl().equals(1))
			return 1;
		if(type.equals(Type.ALARM))
			return 1;
		if(c == null)
			return 0;
		return channelProcessor.getAlarm(c,showValue);
	}


	/**
	 * 限制频繁操作
	 * @param reqDto
	 */
	public boolean canReceive(String deviceCode) {
		Date d = null;
		try {
			d = oprateCache.get(deviceCode);
		} catch (ExecutionException e) {
			e.printStackTrace();
			return false;
		}
    	if(new Date().getTime()-d.getTime()>1000) {
    		System.out.println(deviceCode+"更新太频繁");
    		return false;
    	}
    	return true;
	}
}
